#include "Parser.h"

/*
 *--------------------------------------------------------------------------------------
 *       Class:  Parser
 *      Method:  Parser
 * Description:  Contrói um Parser
 *--------------------------------------------------------------------------------------
 */
Parser::Parser(ulong offset, ulong size, int type)
{
    this->size = size;
    this->type = type;
    this->count = 0;

    /* Se o offset for 0, a primeira palavra ou frase não é ignorada */
    if(offset != 0)
        this->state = IGNORE_FIRST;
    else
        this->state = SKIP_SEPARATORS;
}

/*
 *--------------------------------------------------------------------------------------
 *       Class:  Parser
 *      Method:  ~Parser
 * Description:  Destrói o Parser
 *--------------------------------------------------------------------------------------
 */
Parser::~Parser()
{

}

/*--------------------------------------------------------------------------------------
 *       Class:  Parser
 *      Method:  getTokens
 * Description:  Obtem os tokens de um bloco
 *--------------------------------------------------------------------------------------
 */
Tokens * Parser::getTokens(string *block)
{
    Tokens *tokens = new Tokens;

    bool stop = false;

    for(uint i = 0; i < block->length() && !stop; i++)
    {
        count++;

        char c = block->at(i); /* Caracter corrente */

        bool separator = isSeparator(c); /* Flag que sinaliza um separador */
        bool alnum = isalnum(c); /* Flag que sinaliza um caracter alfanumérico */

        switch(state)
        {
            /* Ignora a primeira palavra ou frase */
            case IGNORE_FIRST:
                if(separator)
                    state = SKIP_SEPARATORS;
                break;

                /* Pula os separadores */
            case SKIP_SEPARATORS:
                if(alnum)
                {
                    tok = new string;

                    if(type == WORD)
                        tok->reserve(MIN_WORD);
                    else
                        tok->reserve(MIN_PHRASE);

                    *tok += c;
                    state = APPEND_TOK;
                }
                break;

                /* Concatena os caracteres no token */
            case APPEND_TOK:
                if(separator)
                {
                    trimString(tok);
                    if(tok->length() > 1)
                        tokens->push_back(tok);
                    else
                        delete tok;

                    if(count > size)
                        stop = true;

                    state = SKIP_SEPARATORS;
                }
                else
                    *tok += c;
                break;
        }
    }

    return tokens;
}

/*--------------------------------------------------------------------------------------
 *       Class:  Parser
 *      Method:  isSeparator
 * Description:  Verifica se c é um separator para palavras ou frases
 *--------------------------------------------------------------------------------------
 */
bool Parser::isSeparator(char c)
{
    if(type == WORD) /* Palavra */
        return (!isalnum(c));

    else
        /* Frase */
        return (c == '.' || c == '!' || c == '?' || c == '\n' || c == '\r' || c == '\t');
}

/*--------------------------------------------------------------------------------------
 *       Class:  Parser
 *      Method:  isFinished
 * Description:  Retorna verdadeiro se o parser terminou sua execução
 *--------------------------------------------------------------------------------------
 */
bool Parser::isFinished()
{
    return (count >= size);
}

/*
 *--------------------------------------------------------------------------------------
 *       Class:  Parser
 *      Method:  trimString
 * Description:  Remove os espaços antes e depois da string
 *--------------------------------------------------------------------------------------
 */
void Parser::trimString(string *str)
{
//    str->erase(str->find_last_not_of(" \n\t\r") + 1);
    str->erase(0, str->find_first_not_of(" \n\t\r"));
}

/*
 *--------------------------------------------------------------------------------------
 *       Class:  Parser
 *      Method:  deleteTokens
 * Description:  Deleta os tokens
 *--------------------------------------------------------------------------------------
 */
void Parser::deleteTokens(Tokens **tokens)
{
    for(uint i = 0; i < (*tokens)->size(); i++)
        delete (*tokens)->at(i);
    delete *tokens;
}

/*--------------------------------------------------------------------------------------
 *       Class:  Parser
 *      Method:  printTokens
 * Description:  Imprime os tokens
 *--------------------------------------------------------------------------------------
 */
void Parser::printTokens(ostream& os, Tokens *tokens)
{
    for(uint i = 0; i < tokens->size(); i++)
        os << *(tokens->at(i)) << endl;
}

